using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using ICSharpCode.TextEditor.Actions;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Util;

namespace ICSharpCode.TextEditor
{
	public class TextAreaClipboardHandler
	{
		public delegate bool ClipboardContainsTextDelegate();

		private TextArea textArea;

		public static ClipboardContainsTextDelegate GetClipboardContainsText;

		private const string LineSelectedType = "MSDEVLineSelect";

		[ThreadStatic]
		private static int SafeSetClipboardDataVersion;

		public bool EnableCut => this.textArea.EnableCutOrPaste;

		public bool EnableCopy => true;

		public bool EnablePaste
		{
			get
			{
				if (!this.textArea.EnableCutOrPaste)
				{
					return false;
				}
				ClipboardContainsTextDelegate getClipboardContainsText = TextAreaClipboardHandler.GetClipboardContainsText;
				if (getClipboardContainsText != null)
				{
					return getClipboardContainsText();
				}
				try
				{
					return Clipboard.ContainsText();
				}
				catch (ExternalException)
				{
					return false;
				}
			}
		}

		public bool EnableDelete => this.textArea.SelectionManager.HasSomethingSelected && !this.textArea.SelectionManager.SelectionIsReadonly;

		public bool EnableSelectAll => true;

		public event CopyTextEventHandler CopyText;

		public TextAreaClipboardHandler(TextArea textArea)
		{
			this.textArea = textArea;
			textArea.SelectionManager.SelectionChanged += DocumentSelectionChanged;
		}

		private void DocumentSelectionChanged(object sender, EventArgs e)
		{
		}

		private bool CopyTextToClipboard(string stringToCopy, bool asLine)
		{
			if (stringToCopy.Length > 0)
			{
				DataObject dataObject = new DataObject();
				dataObject.SetData(DataFormats.UnicodeText, autoConvert: true, stringToCopy);
				if (asLine)
				{
					MemoryStream memoryStream = new MemoryStream(1);
					memoryStream.WriteByte(1);
					dataObject.SetData("MSDEVLineSelect", autoConvert: false, memoryStream);
				}
				if (this.textArea.Document.HighlightingStrategy.Name != "Default")
				{
					dataObject.SetData(DataFormats.Rtf, RtfWriter.GenerateRtf(this.textArea));
				}
				this.OnCopyText(new CopyTextEventArgs(stringToCopy));
				TextAreaClipboardHandler.SafeSetClipboard(dataObject);
				return true;
			}
			return false;
		}

		private static void SafeSetClipboard(object dataObject)
		{
			int version = ++TextAreaClipboardHandler.SafeSetClipboardDataVersion;
			try
			{
				Clipboard.SetDataObject(dataObject, copy: true);
			}
			catch (ExternalException)
			{
				Timer timer = new Timer();
				timer.Interval = 100;
				timer.Tick += delegate
				{
					timer.Stop();
					timer.Dispose();
					if (TextAreaClipboardHandler.SafeSetClipboardDataVersion == version)
					{
						try
						{
							Clipboard.SetDataObject(dataObject, copy: true, 10, 50);
						}
						catch (ExternalException)
						{
						}
					}
				};
				timer.Start();
			}
		}

		private bool CopyTextToClipboard(string stringToCopy)
		{
			return this.CopyTextToClipboard(stringToCopy, asLine: false);
		}

		public void Cut(object sender, EventArgs e)
		{
			if (this.textArea.SelectionManager.HasSomethingSelected)
			{
				if (this.CopyTextToClipboard(this.textArea.SelectionManager.SelectedText) && !this.textArea.SelectionManager.SelectionIsReadonly)
				{
					this.textArea.BeginUpdate();
					this.textArea.Caret.Position = this.textArea.SelectionManager.SelectionCollection[0].StartPosition;
					this.textArea.SelectionManager.RemoveSelectedText();
					this.textArea.EndUpdate();
				}
			}
			else if (this.textArea.Document.TextEditorProperties.CutCopyWholeLine)
			{
				int lineNumberForOffset = this.textArea.Document.GetLineNumberForOffset(this.textArea.Caret.Offset);
				LineSegment lineSegment = this.textArea.Document.GetLineSegment(lineNumberForOffset);
				string text = this.textArea.Document.GetText(lineSegment.Offset, lineSegment.TotalLength);
				this.textArea.SelectionManager.SetSelection(this.textArea.Document.OffsetToPosition(lineSegment.Offset), this.textArea.Document.OffsetToPosition(lineSegment.Offset + lineSegment.TotalLength));
				if (this.CopyTextToClipboard(text, asLine: true) && !this.textArea.SelectionManager.SelectionIsReadonly)
				{
					this.textArea.BeginUpdate();
					this.textArea.Caret.Position = this.textArea.Document.OffsetToPosition(lineSegment.Offset);
					this.textArea.SelectionManager.RemoveSelectedText();
					this.textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToEnd, new TextLocation(0, lineNumberForOffset)));
					this.textArea.EndUpdate();
				}
			}
		}

		public void Copy(object sender, EventArgs e)
		{
			if (!this.CopyTextToClipboard(this.textArea.SelectionManager.SelectedText) && this.textArea.Document.TextEditorProperties.CutCopyWholeLine)
			{
				int lineNumberForOffset = this.textArea.Document.GetLineNumberForOffset(this.textArea.Caret.Offset);
				LineSegment lineSegment = this.textArea.Document.GetLineSegment(lineNumberForOffset);
				string text = this.textArea.Document.GetText(lineSegment.Offset, lineSegment.TotalLength);
				this.CopyTextToClipboard(text, asLine: true);
			}
		}

		public void Paste(object sender, EventArgs e)
		{
			if (!this.textArea.EnableCutOrPaste)
			{
				return;
			}
			int num = 0;
			while (true)
			{
				try
				{
					IDataObject dataObject = Clipboard.GetDataObject();
					if (dataObject == null)
					{
						return;
					}
					bool dataPresent = dataObject.GetDataPresent("MSDEVLineSelect");
					if (!dataObject.GetDataPresent(DataFormats.UnicodeText))
					{
						return;
					}
					string text = (string)dataObject.GetData(DataFormats.UnicodeText);
					if (string.IsNullOrEmpty(text))
					{
						return;
					}
					this.textArea.Document.UndoStack.StartUndoGroup();
					try
					{
						if (this.textArea.SelectionManager.HasSomethingSelected)
						{
							this.textArea.Caret.Position = this.textArea.SelectionManager.SelectionCollection[0].StartPosition;
							this.textArea.SelectionManager.RemoveSelectedText();
						}
						if (dataPresent)
						{
							int column = this.textArea.Caret.Column;
							this.textArea.Caret.Column = 0;
							if (!this.textArea.IsReadOnly(this.textArea.Caret.Offset))
							{
								this.textArea.InsertString(text);
							}
							this.textArea.Caret.Column = column;
						}
						else
						{
							this.textArea.InsertString(text);
						}
					}
					finally
					{
						this.textArea.Document.UndoStack.EndUndoGroup();
					}
					return;
				}
				catch (ExternalException)
				{
					if (num > 5)
					{
						throw;
					}
				}
				num++;
			}
		}

		public void Delete(object sender, EventArgs e)
		{
			new Delete().Execute(this.textArea);
		}

		public void SelectAll(object sender, EventArgs e)
		{
			new SelectWholeDocument().Execute(this.textArea);
		}

		protected virtual void OnCopyText(CopyTextEventArgs e)
		{
			if (this.CopyText != null)
			{
				this.CopyText(this, e);
			}
		}
	}
}
